#include"write_delay_control.h"

//该函数真正执行在当前周期应该执行的写入操作，执行后清空该slot，同时自动移动头指针
void WriteControlModule::do_the_real_thing() {
    this->head_pointer->write_and_clear();
    //执行后，自动向后移动一个slot，自行运行传送带
    this->head_pointer = this->head_pointer->get_next_ptr();
}

//在环上通过delay确定该写入请求所属的slot
inline void rolling_on_the_ring(WriteReq* wrq, int delay, ControlSlot* head_pointer) {
    ControlSlot* temp_ptr = head_pointer;
    //通过delay确定从头节点向后转移的次数
    for (int i = 0; i < delay - 1; i++) {
        temp_ptr = temp_ptr->get_next_ptr();
    }
    std::cout << "Posting write request with delay " << delay << " to the corresponding slot." << std::endl;
    wrq->print_info();
    //此时temp_ptr指向将要操作的slot
    temp_ptr->set_buckets(wrq);
}//这里有问题？？

//TODO:之后要通过参数对该函数进行重载，开放对不同类型写入的API
//该版本为向量寄存器写入请求提交
void WriteControlModule::post_write_req(int reg_id, std::vector<uint64_t>* value, int delay) {
    WriteReq_VR* wrvr = new WriteReq_VR(reg_id, value, this->RF);
    rolling_on_the_ring(wrvr, delay, this->head_pointer);
}

//该版本为标量寄存器写入请求提交
void WriteControlModule::post_write_req(int reg_id, uint64_t value, int delay) {
    WriteReq_SR* wrsr = new WriteReq_SR(reg_id, value, this->RF);
    std::cout<< "write_req_SR reg_id:"<< std::dec <<reg_id <<  ",write_req_SR value:" << value<<std::endl;
    wrsr->print_info();
    rolling_on_the_ring(wrsr, delay, this->head_pointer);
}

//向量AM写入请求提交
void WriteControlModule::post_write_req(addr_size_t addr, std::vector<uint64_t>* value1, int8_t access_size, int delay) {
    WriteReq_VLDST* wrvldst = new WriteReq_VLDST(value1, addr, access_size, this->AM);
    rolling_on_the_ring(wrvldst, delay, this->head_pointer);
}

//标量SM写入请求提交
void WriteControlModule::post_write_req(addr_size_t addr, uint64_t value1, int8_t access_size, int delay) {
    std::cout << "Posting scalar memory write request at address " << std::hex << addr << " with value " << std::dec << value1 << " and access size " << (access_size == HW ? "HW" : "W") << " after delay " << delay << "." << std::endl;
    WriteReq_SLDST* wrsldst = new WriteReq_SLDST(value1, addr, access_size, this->SM);
    rolling_on_the_ring(wrsldst, delay, this->head_pointer);
}

//向量混洗load操作
void WriteControlModule::post_write_req_m(int reg_id, std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int mod_num, bool zero_one, int delay) {
    //先检查当前周期中，是否已有混洗操作的req被提交
    //因为对于VLDST0和VLDST1来说，提交请求的顺序是不确定的
    WriteReq* wrq = this->head_pointer->merge_req(true);
    WriteReq_VLDST_LDM* wrvdlm;
    if (wrq == nullptr) {
        //这是第一个请求，需要创建一个新的Req
        wrvdlm = new WriteReq_VLDST_LDM(mod_num, this->RF);
        if (zero_one) {
            //vldst0
            wrvdlm->add_LDST0_info(value1, value2, reg_id);
        } else {
            //vldst1
            wrvdlm->add_LDST1_info(value1, value2, reg_id);
        }
    } else {
        wrvdlm = dynamic_cast<WriteReq_VLDST_LDM*>(wrq);
        if (zero_one) {
            //vldst0
            wrvdlm->add_LDST0_info(value1, value2, reg_id);
        } else {
            //vldst1
            wrvdlm->add_LDST1_info(value1, value2, reg_id);
        }
    }
    rolling_on_the_ring(wrvdlm, delay, this->head_pointer);
}

//向量混洗store操作
void WriteControlModule::post_write_req_m(addr_size_t addr, std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int mod_num, bool zero_one, int delay) {
    //先检查当前周期中，是否已有混洗操作的req被提交
    //因为对于VLDST0和VLDST1来说，提交请求的顺序是不确定的
    WriteReq* wrq = this->head_pointer->merge_req(false);
    WriteReq_VLDST_STM* wrvstm;
    if (wrq == nullptr) {
        //这是第一个请求，需要创建一个新的Req
        wrvstm = new WriteReq_VLDST_STM(mod_num, this->AM);
        if (zero_one) {
            //vldst0
            wrvstm->add_LDST0_info(value1, value2, addr);
        } else {
            //vldst1
            wrvstm->add_LDST1_info(value1, value2, addr);
        }
    } else {
        wrvstm = dynamic_cast<WriteReq_VLDST_STM*>(wrq);
        if (zero_one) {
            //vldst0
            wrvstm->add_LDST0_info(value1, value2, addr);
        } else {
            //vldst1
            wrvstm->add_LDST1_info(value1, value2, addr);
        }
    }
    rolling_on_the_ring(wrvstm, delay, this->head_pointer);
}

void ControlSlot::set_next_ptr(ControlSlot* ptr) {
    this->next_ptr = ptr;
}

ControlSlot*    ControlSlot::get_next_ptr() {
    return this->next_ptr;
}

void ControlSlot::write_and_clear() {
    //写入时按GC的大小，从小至大的顺序写入，故符合map的存储顺序，无需执行排序
    for(auto it = this->buckets->begin(); it != this->buckets->end(); ++it) {
        for (auto req : it->second) {
            req->write();
            // delete req;
        }
        it->second.clear();
    }
    this->buckets->clear();
}

void ControlSlot::set_buckets(WriteReq* wr) {
    auto it = this->buckets->find(global_clock);
    if (it != this->buckets->end()) {
        it->second.push_back(wr);
    } else {
        (*buckets)[global_clock].push_back(wr);
    }
}

WriteReq* ControlSlot::merge_req(bool ldst) {
    auto it = this->buckets->find(global_clock);
    if (it != this->buckets->end()) {
        if (ldst) {
            //load
            for (auto req : it->second) {
                if (typeid(req) == typeid(WriteReq_VLDST_LDM)) {
                    return req;
                }
            }
            return nullptr;
        } else {
            //store
            for (auto req : it->second) {
                if (typeid(req) == typeid(WriteReq_VLDST_STM)) {
                    return req;
                }
            }
            return nullptr;
        }
        
    } else {
        return nullptr;
    }
}

void WriteReq_VLDST_LDM::add_LDST0_info(std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, int reg_id_1) {
    this->value1 = value1;
    this->value2 = value2;
    this->dst_reg_1 = reg_id_1;
}

void WriteReq_VLDST_LDM::add_LDST1_info(std::vector<uint64_t>* value3, std::vector<uint64_t>* value4, int reg_id_2) {
    this->value3 = value3;
    this->value4 = value4;
    this->dst_reg_2 = reg_id_2;
}

void WriteReq_VLDST_STM::add_LDST0_info(std::vector<uint64_t>* value1, std::vector<uint64_t>* value2, addr_size_t addr1) {
    this->value1 = value1;
    this->value2 = value2;
    this->addr_1 = addr1;
}

void WriteReq_VLDST_STM::add_LDST1_info(std::vector<uint64_t>* value3, std::vector<uint64_t>* value4, addr_size_t addr2) {
    this->value3 = value3;
    this->value4 = value4;
    this->addr_2 = addr2;
}